package cn.geminis.fabric.chaincode;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.shim.ChaincodeBase;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.ResponseUtils;

import java.nio.charset.StandardCharsets;

/**
 * @author puddi
 */
@Slf4j
public class CommonChaincode extends ChaincodeBase {

    private final static String TXID_PREFIX = "TXID_";

    @Override
    public Response init(ChaincodeStub chaincodeStub) {
        log.info("Init");
        return ResponseUtils.newSuccessResponse();
    }

    @Override
    public Response invoke(ChaincodeStub chaincodeStub) {
        var function = chaincodeStub.getFunction();
        var args = chaincodeStub.getParameters();
        log.info("Invoke function:{}, args:{}", function, args);
        switch (function) {
            case "get":
                if (args.size() < 1) {
                    throw new RuntimeException("expect 1 args");
                }
                var id = args.get(0);
                var value = get(chaincodeStub, id);
                return ResponseUtils.newSuccessResponse(id, value.getBytes(StandardCharsets.UTF_8));
            case "set":
                if (args.size() < 2) {
                    throw new RuntimeException("expect 2 args");
                }
                set(chaincodeStub, args.get(0), args.get(1));
                return ResponseUtils.newSuccessResponse(chaincodeStub.getTxId());
            case "delete":
                if (args.size() < 1) {
                    throw new RuntimeException("expect 1 args");
                }
                delete(chaincodeStub, args.get(0));
                return ResponseUtils.newSuccessResponse(chaincodeStub.getTxId());
            default:
                return ResponseUtils.newErrorResponse(String.format("unknown function:%s", function));
        }
    }

    private String get(ChaincodeStub chaincodeStub, @NonNull String id) {
        log.info("get value id:{}", id);
        String value = chaincodeStub.getStringState(id);
        if (value == null) {
            throw new RuntimeException(String.format("Value not found: %s", id));
        }
        return value;
    }

    private void set(ChaincodeStub chaincodeStub, @NonNull String id, @NonNull String value) {
        var txid = chaincodeStub.getTxId();
        chaincodeStub.putStringState(id, value);
        chaincodeStub.putStringState(TXID_PREFIX + id, txid);
        log.info("set value txid:{}, id:{}, value:{}", txid, id, value);
    }

    private void delete(ChaincodeStub chaincodeStub, @NonNull String id) {
        log.info("delete value id:{}", id);
        chaincodeStub.delState(id);
        chaincodeStub.delState(TXID_PREFIX + id);
    }

    public static void main(String[] args) {
        log.info("start");
        new CommonChaincode().start(args);
    }

}
